<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
</head>

<body>
    <div id="app">
        <input v-model="demo.a" />
        <button v-click="add">新增</button>
        <h4 v-bind="demo.a"></h4>
    </div>
    <script>
        function myMve(options) {
            this.init(options);
        }
        myMve.prototype.init = function(options) {
            this.$dom = document.querySelector(options.el);
            this.$methods = options.methods;
            this.$data = options.data;
            //依赖对象
            this.binding = {};
            //观察
            this.observe( this.$data);
            //解析dom，收集依赖
            this.compile(this.$dom);
        };
        myMve.prototype.compile = function(dom) {
            let nodes = dom.children;
            for (let i = 0; i < nodes.length; i++) {
                let node = nodes[i];
                if (node.children.length>0) {
                    this.compile(node);
                }
                if (node.hasAttribute('v-model')) {
                    const attr = node.getAttribute('v-model');
                    this.binding[attr].push(new Watcher(node, this, 'value',attr));
                    node.addEventListener('input', () => {
                        this.$data[attr] = node.value;
                    });
                }
                if (node.hasAttribute('v-click')) {
                    const attr = node.getAttribute('v-click');
                    node.onclick = (() => {
                        return this.$methods[attr].bind(this.$data);
                    })();
                }
                if (node.hasAttribute('v-bind')) {
                    const attr = node.getAttribute('v-bind');
                    this.binding[attr].push(new Watcher(node, this, 'innerHTML',attr));
                }
            }
        };
        myMve.prototype.observe = function(data) {
            Object.keys(data).forEach(key => {
                this.binding[key] = [];
                let value=data[key];
                let binding=this.binding[key]
                if (data[key] instanceof Object) {
                    this.observe(value);
                } else {
                    Object.defineProperty(data, key, {
                        configurable: true,
                        enumerable: true,
                        get() {
                            return value;
                        },
                        set(newVal) {
                            if (value !== newVal) {
                                value = newVal;
                                console.log(this);
                                binding.forEach(fn => {
                                    fn.update();
                                });
                            }
                        },
                    });
                }
            });
        };

        function Watcher(el, vm, attr, exp) {
            this.$el = el;
            this.$vm = vm;
            this.$attr = attr;
            this.$exp = exp;
            this.update()
        }
        Watcher.prototype.update = function() {
            this.$el[this.$attr] = this.$vm.$data[this.$exp];
        };
        window.onload=function () {
            var app = new myMve({
                el: '#app',
                data: {
                    number: 1,
                    dmeo:{
                        a:1
                    }
                },
                methods: {
                    add: function() {
                        console.log(this.number);
                        this.demo.a++;
                    },
                },
            });
        }
 
    </script>
</body>

</html>